//#define ESP32
#include <NmraDcc.h>

// 引脚定义
// D2 接收 DCC 信号 (中断引脚)
#define DCC_RX_PIN    2   
// D7 发送响应信号
#define DCC_ACK_PIN     7   
// DCC 解码器对象
NmraDcc Dcc;

// DCC 配置参数
uint8_t DccCV29 = 0;         // CV29 默认值

// 机车状态结构
struct Locomotive {
  uint16_t address = 3;      // 默认地址
  uint8_t speed = 0;         // 当前速度(0-126)
  uint8_t direction = 1;     // 方向(0=反向,1=正向)
  bool functions[13] = {0};  // 功能状态F0-F12
  uint8_t switchState = 0;   // 开关状态
} loco;

// 回调函数声明
void notifySpeedDirection(uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps);
void notifyFunction(uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState);
void notifyDccReset(uint8_t hardReset);
void notifyCVAck(void);

void setup() {
  // 初始化串口
  Serial.begin(115200);
  Serial.println("DCC Decoder with Full Control");

  // 配置引脚
  pinMode(DCC_RX_PIN, INPUT_PULLUP);
  pinMode(DCC_ACK_PIN, OUTPUT);
  digitalWrite(DCC_ACK_PIN, LOW);
  
  // 初始化 DCC 接收器
  Dcc.pin(DCC_RX_PIN, 0);  // 使用 INT0 中断
  Dcc.init(MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0); 
 
}

void loop() {
  Dcc.process();  // 处理 DCC 数据
}

// ================ 速度与方向回调 ================
void notifySpeedDirection(
  uint16_t Addr, 
  DCC_ADDR_TYPE AddrType,
  uint8_t Speed, 
  DCC_DIRECTION Dir,
  DCC_SPEED_STEPS SpeedSteps
) {
  // 仅处理匹配本设备地址的指令
  if(Addr != loco.address) return;
  
  loco.speed = Speed;
  loco.direction = (Dir == DCC_DIR_FWD);
 
  Serial.print("Speed: ");
  Serial.print(Speed);
  Serial.print(" | Direction: ");
  Serial.print(Dir == DCC_DIR_FWD ? "FWD" : "REV");
  Serial.print(" | Steps: ");
  Serial.println(SpeedSteps);
  
 
}

// ================ 功能开关回调 ================
void notifyFunction(
  uint16_t Addr, 
  DCC_ADDR_TYPE AddrType,
  FN_GROUP FuncGrp, 
  uint8_t FuncState
) {
  // 仅处理匹配本设备地址的指令
  if(Addr != loco.address) return;
  
  // 处理FN 
  switch(FuncGrp) {
    case FN_0_4:
      loco.functions[0] = (FuncState & FN_BIT_00) ? 1 : 0;
      loco.functions[1] = (FuncState & FN_BIT_01) ? 1 : 0;
      loco.functions[2] = (FuncState & FN_BIT_02) ? 1 : 0;
      loco.functions[3] = (FuncState & FN_BIT_03) ? 1 : 0;
      loco.functions[4] = (FuncState & FN_BIT_04) ? 1 : 0;
      break;
      
    case FN_5_8:
      loco.functions[5] = (FuncState & FN_BIT_05) ? 1 : 0;
      loco.functions[6] = (FuncState & FN_BIT_06) ? 1 : 0;
      loco.functions[7] = (FuncState & FN_BIT_07) ? 1 : 0;
      loco.functions[8] = (FuncState & FN_BIT_08) ? 1 : 0;
      break;
      
    case FN_9_12:
      loco.functions[9] = (FuncState & FN_BIT_09) ? 1 : 0;
      loco.functions[10] = (FuncState & FN_BIT_10) ? 1 : 0;
      loco.functions[11] = (FuncState & FN_BIT_11) ? 1 : 0;
      loco.functions[12] = (FuncState & FN_BIT_12) ? 1 : 0;
      break;
  }
  
  Serial.print("功能指令 | 地址:");
  Serial.print(Addr);
  Serial.print(" 功能组:");
  Serial.print(FuncGrp);
  Serial.print(" 状态:");
  Serial.println(FuncState, BIN);

}

// ================ DCC复位回调 ================
void notifyDccReset(uint8_t hardReset) {
  Serial.println(hardReset ? "Hard Reset" : "Soft Reset");
  // 这里可以添加硬件复位逻辑
}


// This function is called by the NmraDcc library when a DCC ACK needs to be sent
void notifyCVAck(void)
{
  Serial.println("notifyCVAck") ;
  // Configure the DCC CV Programing ACK pin for an output
  pinMode( DCC_ACK_PIN, OUTPUT );
  // Generate the DCC ACK 60mA pulse
  digitalWrite( DCC_ACK_PIN, HIGH );
  // The DCC Spec says 6ms but 10 makes sure... ;)
  delay( 10 );  
  digitalWrite( DCC_ACK_PIN, LOW );
}
